/*
 * ManejadorInstrucciones.cpp
 *
 *  Created on: 10/09/2010
 *      Author: julfc
 */

#include "ManejadorInstrucciones.h"

ManejadorInstrucciones::ManejadorInstrucciones() {
}

bool ManejadorInstrucciones::almacenamiento(QTextEdit* bigEditor){
	ManejadorConfiguracion manejadorConf;
	manejadorConf.limpiarConfiguracion();
    //Creo las matrices y las guardo.
    //Encriptador encripta;
	Encriptador *encripta = EncipSingleton<Encriptador>::GetInstance();
    //encripta->crearMatrices();
	vector<string> config=  manejadorConf.obtenerParamsLibspopc();
	ImportadorMails importador;
	return importador.bajarmails(config[0],config[1],config[2],config[3],"indiceUnico.dat", bigEditor);
}

QString ManejadorInstrucciones::derivarCreacionIndices(QString indices) {
  Parser parser;
  QString output;
  QString trimeada = indices.trimmed();
  QStringList partes = trimeada.split(" ", QString::SkipEmptyParts);
  string instruccion = partes.at(1).toStdString();
  parser.upper(instruccion);
  bool exito;
  ManejadorConfiguracion manejadorConf;
  if (instruccion.compare("CREARCLASIFICACION") == 0) {
    if(partes.size() < 3) {
      output += QString("Falta parametro de Clasificacion: ");
      output += indices;
    } else {
      string username = partes.at(0).toStdString();
      string filtro = partes.at(2).toStdString();
      bool valida = parser.ValidarFiltro(filtro);
      if (!valida){
        output += QString("Los paramateros del filtro son incorrectos: ");
        output += partes.at(2);
      } else {
        string nombreFiltro;
        nombreFiltro.assign(parser.ObtenerNombreFiltro(filtro, false));
        parser.upper(nombreFiltro);
        if (nombreFiltro.compare("IUC") == 0){
          output += QString("IUC: Nombre de filtro invalido.");
        } else {
          parser.upper(nombreFiltro);
          if(nombreFiltro.compare("ORIGEN") == 0) {
            exito = AgregarClasificacion(1, username);
          } else if(nombreFiltro.compare("DESTINO") == 0) {
            exito = AgregarClasificacion(2, username);
          } else if(nombreFiltro.compare("FECHA") == 0) {
            exito = AgregarClasificacion(3, username);
          } else if(nombreFiltro.compare("ASUNTO") == 0) {
            exito = AgregarClasificacion(4, username);
          } else {
            output += QString("El parametro es incorrecto: ");
            output += QString(partes.at(2));
            return output;
          }
          if(exito) {
            output += QString("La instruccion se realizo exitosamente: ");
            output += indices;
          }
          else {
            output += QString("La instruccion no pudo ser realizada: ");
            output += indices;
          }
        }
      }
    }
  } else if (instruccion.compare("CREARSELECCION") == 0) {
    if(partes.size() < 3) {
      output += QString("Falta parametro de Seleccion: ");
      output += indices;
    }
    else {
      string username = partes.at(0).toStdString();
      string filtro = partes.at(2).toStdString();
      bool valida = parser.ValidarFiltro(filtro);
      if (!valida){
        output += QString("Los paramateros del filtro son incorrectos: ");
        output += partes.at(2);
      } else {
        string nombreFiltro;
        string opcionesFiltro;
        nombreFiltro.assign(parser.ObtenerNombreFiltro(filtro,true));
        if (nombreFiltro == "IUC") {
          output += QString("IUC: Nombre de filtro invalido.");
        }
        else {
          opcionesFiltro.assign(parser.ObtenerCondicionFiltro(filtro));
          parser.upper(nombreFiltro);
          if(nombreFiltro.compare("ORIGEN") == 0) {
            exito = AgregarSeleccion(1, opcionesFiltro, username);
          }
          else if(nombreFiltro.compare("DESTINO") == 0) {
            exito = AgregarSeleccion(2, opcionesFiltro, username);
          }
          else if(nombreFiltro.compare("ASUNTO") == 0) {
            string asuntoParseado = parser.parsearAsunto(opcionesFiltro);
            if (asuntoParseado == "") {
              output += QString("El valor para el filtro por ASUNTO no puede ser vacio: ");
              output += indices;
              return output;
            }
            exito = AgregarSeleccion(4, opcionesFiltro, username);
          }
          else if(nombreFiltro.compare("FECHA") == 0) {
            string fechaParseada = parser.parsearFecha(opcionesFiltro);
            if (fechaParseada == "") {
              output += QString("La fecha ingresada es incorrecta: ");
              output += indices;
              return output;
            }
            exito = AgregarSeleccion(3, opcionesFiltro, username);
          } else {
            output += QString("El parametro es incorrecto: ");
            output += indices;
            return output;
          }
          if(exito) {
            output += QString("La instruccion se realizo exitosamente: ");
            output += indices;
          }
          else {
            output += QString("La instruccion no pudo ser realizada: ");
            output += indices;
          }
        }
      }
    }
  }
  return output;
}

bool ManejadorInstrucciones::AgregarClasificacion(int filtro, string username){
	ManejadorConfiguracion manejadorConf;
	char archivo[64];
	strcpy(archivo, manejadorConf.obtenerParamsLibspopc()[3].c_str());
	ManejadorArchivoUnico manejadorArchivoUnico(archivo,ABRIR);
	vector<FiltroSeleccion> resultados;
	string nombreArchivoStr;
	nombreArchivoStr.append(ManejadorConfiguracion::TIPO_CLASIFICACION + ".");

	switch(filtro){
	case 1:
		manejadorConf.crearFiltro(ManejadorConfiguracion::TIPO_CLASIFICACION,ManejadorConfiguracion::ORIGEN,username);
		resultados=manejadorArchivoUnico.buscarValoresFiltroClasificacion(FROM);
		nombreArchivoStr.append(ManejadorConfiguracion::ORIGEN + ".");
		break;
	case 2:
		manejadorConf.crearFiltro(ManejadorConfiguracion::TIPO_CLASIFICACION,ManejadorConfiguracion::DESTINO,username);
		resultados = manejadorArchivoUnico.buscarValoresFiltroClasificacion(TO);
		nombreArchivoStr.append(ManejadorConfiguracion::DESTINO + ".");
		break;
	case 3:
		manejadorConf.crearFiltro(ManejadorConfiguracion::TIPO_CLASIFICACION,ManejadorConfiguracion::FECHA,username);
		resultados = manejadorArchivoUnico.buscarValoresFiltroClasificacion(DATE);
		nombreArchivoStr.append(ManejadorConfiguracion::FECHA + ".");
		break;
	case 4:
		manejadorConf.crearFiltro(ManejadorConfiguracion::TIPO_CLASIFICACION,ManejadorConfiguracion::ASUNTO,username);
		resultados = manejadorArchivoUnico.buscarValoresFiltroClasificacion(SUBJECT);
		nombreArchivoStr.append(ManejadorConfiguracion::ASUNTO + ".");
		break;
	};
	nombreArchivoStr.append(username);
	string nombreArbol = manejadorConf.obtenerValor(nombreArchivoStr);
	char strArbol[256];
	strcpy(strArbol, nombreArbol.c_str());
	nombreArchivoStr.append(".LISTA");
	string nombreArchivoLista = manejadorConf.obtenerValor(nombreArchivoStr);
	char strLista[256];
	strcpy(strLista, nombreArchivoLista.c_str());

	ArbolBSharpStringLong arbolClasif;
	ManejadorArchivoClasificacion manejadorArchivoClasificacion(strLista,CREAR);
	arbolClasif.Crear(strArbol);

	for(int i=0; i< resultados.size(); i++){
		RegistroBSharpStringLong registro;
		long numBloque = manejadorArchivoClasificacion.escribirListaDemails(i+1,resultados[i].valores);
		registro.clave = resultados[i].clave;
		registro.valor = numBloque;
		registro.valorExtra = i+1;
		arbolClasif.InsertarRegistro(registro);
	}

	return true;
}

bool ManejadorInstrucciones::AgregarSeleccion(int filtro, string valor, string username){
	ManejadorConfiguracion manejadorConf;
	Parser parser;
	char archivo[64];
	strcpy(archivo, manejadorConf.obtenerParamsLibspopc()[3].c_str());
	ManejadorArchivoUnico manejadorArchivoUnico(archivo,ABRIR);
	FiltroSeleccion resultados;
	string nombreArchivoStr;
	string fechaParseada;
	string asuntoParseado;
	nombreArchivoStr.append(ManejadorConfiguracion::TIPO_SELECCION + ".");

	switch(filtro){
	case 1:
		manejadorConf.crearFiltro(ManejadorConfiguracion::TIPO_SELECCION,ManejadorConfiguracion::ORIGEN,valor,username);
		resultados = manejadorArchivoUnico.buscarValoresFiltroSeleccion(FROM,valor);
		nombreArchivoStr.append(ManejadorConfiguracion::ORIGEN + ".");
		break;
	case 2:
		manejadorConf.crearFiltro(ManejadorConfiguracion::TIPO_SELECCION,ManejadorConfiguracion::DESTINO,valor,username);
		resultados = manejadorArchivoUnico.buscarValoresFiltroSeleccion(TO,valor);
		nombreArchivoStr.append(ManejadorConfiguracion::DESTINO + ".");
		break;
	case 3:
		fechaParseada = parser.parsearFecha(valor);
		manejadorConf.crearFiltro(ManejadorConfiguracion::TIPO_SELECCION,ManejadorConfiguracion::FECHA,valor,username);
		resultados = manejadorArchivoUnico.buscarValoresFiltroSeleccion(DATE,fechaParseada);
		nombreArchivoStr.append(ManejadorConfiguracion::FECHA + ".");
		break;
	case 4:
		asuntoParseado = parser.parsearAsunto(valor);
		manejadorConf.crearFiltro(ManejadorConfiguracion::TIPO_SELECCION,ManejadorConfiguracion::ASUNTO,valor,username);
		resultados = manejadorArchivoUnico.buscarValoresFiltroSeleccion(SUBJECT,asuntoParseado);
		nombreArchivoStr.append(ManejadorConfiguracion::ASUNTO + ".");
		break;
	}
	nombreArchivoStr.append(valor + ".");
	nombreArchivoStr.append(username);
	string nombreArchivoConf= manejadorConf.obtenerValor(nombreArchivoStr);
	char str[256];
	strcpy(str, nombreArchivoConf.c_str());
	ArbolBSharp arbolClasif;
	arbolClasif.Crear(str);
    for(int i=0; i< resultados.valores.size(); i++){
    	RegistroBSharp registro;
    	registro.clave = resultados.valores[i];
    	registro.valor = resultados.valores[i];
    	arbolClasif.InsertarRegistro(registro);
	 }
	return true;
}

QString ManejadorInstrucciones::derivarBusquedas(QString filtros) {
  Parser parser;
  QString output;
  QString trimeada = filtros.trimmed();
  QStringList partes = trimeada.split(" ", QString::SkipEmptyParts);
  string instruccion = partes.at(1).toStdString();
  parser.upper(instruccion);
  bool exito;
  if (instruccion.compare("BUSCAR") == 0) {
    if(partes.size() == 2) {
      output += QString("Falta parametro de Clasificacion: ");
      output += filtros;
    } else {
      bool filtroValido = false;
      string username = partes.at(0).toStdString();
      // Validar todos los filtros sino devolver error.
      for (int i = 2; i < partes.size(); i++) {
        filtroValido = parser.ValidarFiltro(partes.at(i).toStdString().c_str());
        if (!filtroValido) {
          output += QString("El filtro no es valido: ");
          output += filtros;
          return output;
        }
      }
      vector<CriterioBusqueda> criterios;
      for (int i = 2; i < partes.size(); i++){
        CriterioBusqueda criterio;
        string filtroBusqueda = partes.at(i).toStdString();
        if(parser.EsBusquedaClasificacion(filtroBusqueda)) {
          //SI es busqueda de clasificacion, el formato es [nombreFiltro=condicion] que es igual al de crear filtro seleccion
          string nomFiltro;
          nomFiltro.assign(parser.ObtenerNombreFiltro(filtroBusqueda, true));
          parser.upper(nomFiltro);
          criterio.NombreFiltro.assign(nomFiltro);
          string condFiltro;
          if (criterio.NombreFiltro == "FECHA") {
            condFiltro = parser.parsearFecha(parser.ObtenerCondicionFiltro(filtroBusqueda));
            if (condFiltro == "") {
              output += QString("La fecha ingresada es incorrecta: ");
              output += filtros;
              return output;
            }
          } else if (criterio.NombreFiltro == "ASUNTO") {
            condFiltro = parser.parsearAsunto(parser.ObtenerCondicionFiltro(filtroBusqueda));
            if (condFiltro == "") {
              output += QString("El ASUNTO ingresado no puede ser vacio: ");
              output += filtros;
              return output;
            }
          } else {
            condFiltro.assign(parser.ObtenerCondicionFiltro(filtroBusqueda));
          }
          criterio.valorFiltro.assign(condFiltro);
        } else {
          string nomFiltro;
          nomFiltro.assign(parser.ObtenerNombreFiltro(filtroBusqueda, false));
          criterio.NombreFiltro.assign(nomFiltro);
        }
        criterios.push_back(criterio);
      }
      exito = buscar(criterios, username, output);
      if (exito) {
        output += QString("La instruccion se realizo exitosamente: ");
        output += filtros;
      }
      else {
        output += QString("La instruccion no pudo ser realizada: ");
        output += filtros;
      }
    }
  }
  return output;
}

bool ManejadorInstrucciones::buscar(vector<CriterioBusqueda> criterios,
    string username, QString &output){
  vector<long> busquedaResultado = BuscarInterno(criterios[0], username);
  Parser parser;

  if(busquedaResultado.size() == 0) {
    output += QString("La busqueda retorno sin valores.");
    output += QString("\n");
  } else {
    vector<long> busquedaContinua;
    for(unsigned int i = 1; i < criterios.size(); i++) {
      busquedaContinua = BuscarInterno(criterios[i], username);
      busquedaResultado = InterseccionResultados(busquedaResultado, busquedaContinua);

      if(busquedaResultado.empty()) {
        output += QString("La busqueda retorno sin valores.");
        output += QString("\n");
        return true;
      }
    }

    output += QString("Los IDs de los mails en los que se encontro el termino son: \n");
    for(unsigned int j = 0; j < busquedaResultado.size(); j++) {
      string busquedaRes = parser.integerToString(busquedaResultado[j]);
      output += QString(busquedaRes.c_str());
      output += QString(", ");
    }
    output += QString("\n");
  }
  return true;
}

vector<long> ManejadorInstrucciones::InterseccionResultados(vector<long> lista1, vector<long> lista2){
	vector<long> listaResultado;
	for(int i= 0; i < lista1.size(); i++){
		for(int j= 0; j< lista2.size(); j++){
			if(lista1[i] == lista2[j])
				listaResultado.push_back(lista2[j]);
		}
	}
	return listaResultado;
}

vector<long> ManejadorInstrucciones::BuscarInterno(CriterioBusqueda criterio, string username){
	vector<long> vectorNulo;
	ManejadorConfiguracion manejadorConf;
	string nombreArchivoFiltro;
	string nombreFiltroTipado;
	if(criterio.valorFiltro != ""){
		if (criterio.NombreFiltro== "IUC"){
			return BuscarIUC(criterio);
		}
		//busca por filtro de Clasificacion
		nombreFiltroTipado.append(ManejadorConfiguracion::TIPO_CLASIFICACION);
		nombreFiltroTipado.append("." + criterio.NombreFiltro);
		nombreFiltroTipado.append("." + username);

		nombreArchivoFiltro = manejadorConf.obtenerValor(nombreFiltroTipado);

		if(nombreArchivoFiltro != "")
		{
			ArbolBSharpStringLong arbol;
			char nombreArchivoArbol[256];
			char nombreArchivoLista[256];

			nombreFiltroTipado.append(".LISTA");
			string nombreArchivoListaStr = manejadorConf.obtenerValor(nombreFiltroTipado);

			strcpy(nombreArchivoArbol, nombreArchivoFiltro.c_str());
			strcpy(nombreArchivoLista, nombreArchivoListaStr.c_str());
			arbol.Abrir(nombreArchivoArbol);

			RegistroBSharpStringLong registro = arbol.ObtenerRegistro(criterio.valorFiltro);

			if(registro.valor != -1)
			{
				ManejadorArchivoClasificacion manejadorClasificacion(nombreArchivoLista, ABRIR);
				return manejadorClasificacion.leerListaDeMails(registro.valor, registro.valorExtra);
			}
			else
			{
				cout << "No se encontro el valor en el indice de Clasificacion" << endl;
				return vectorNulo;
			}
		}
		else
		{
			cout << "No se encontro el indice de Clasificacion" << endl;
			return vectorNulo;
		}
	}
	else{
		//busca por filtro de Seleccion
		nombreFiltroTipado.append(ManejadorConfiguracion::TIPO_SELECCION);
		nombreFiltroTipado.append("." + criterio.NombreFiltro);
		nombreFiltroTipado.append("." + username);

		nombreArchivoFiltro = manejadorConf.obtenerValor(nombreFiltroTipado);

		if(nombreArchivoFiltro != "")
		{
			ArbolBSharp arbol;
			char nombreArchivoArbol[256];

			strcpy(nombreArchivoArbol, nombreArchivoFiltro.c_str());
			arbol.Abrir(nombreArchivoArbol);

			return arbol.RecorrerOrdenado();
		}
		else
		{
			cout << "No se encontro el indice de Seleccion" << endl;
			return vectorNulo;
		}
	}
}

vector<long> ManejadorInstrucciones::BuscarIUC(CriterioBusqueda criterio){
	vector<string> busqueda;
	vector<long> resultados;
	Parser parser;
	ArbolBSharp arbol;
	arbol.Abrir("indiceUnico.dat");
	RegistroBSharp registro;

	busqueda = parser.Split(criterio.valorFiltro,",");
	for(int i=0; i < busqueda.size(); i++){
		int id = atoi(busqueda[i].c_str());
		registro = arbol.ObtenerRegistro(id);
		if(registro.clave!= -1){
			resultados.push_back(registro.clave);
		}
	}
	return resultados;
}

void ManejadorInstrucciones::MostrarMail(long id, QString &output)
{
	ArbolBSharp arbol;
	arbol.Abrir("indiceUnico.dat");

	RegistroBSharp registro;
	registro = arbol.ObtenerRegistro(id);

	if(registro.clave !=-1){

	ManejadorConfiguracion manejadorConf;
	char archivo[64];
	strcpy(archivo, manejadorConf.obtenerParamsLibspopc()[3].c_str());

	ManejadorArchivoUnico manejUnico(archivo,ABRIR);
	char* mail = manejUnico.obtenerMail(id, registro.valor);
	Mail mailClass;
	string mailStr = mailClass.getBody(mail);
	// cout << "El mail obtenido es: " << endl << endl;
	output += "\n\n";
	output += "--------> El contenido del mail es:";
	output += "\n\n";
	output += mailStr.c_str();
	// cout << mailStr << endl;
	}
	else {
	  output += " ---> No se encontro el Mail, el ID no es valido.";
		// cout << "No se encontró el Mail, eL Id no es valido" << endl;
	}
}

bool ManejadorInstrucciones::EliminarMail(long int id){
	ArbolBSharp arbol;
	arbol.Abrir("indiceUnico.dat");

	RegistroBSharp registro;
	registro = arbol.ObtenerRegistro(id);

	if(registro.clave !=-1){
		arbol.EliminarRegistro(registro.clave);
		ManejadorConfiguracion manejadorConf;
		int long cantMails = manejadorConf.obtenerCantidadMails();
		cantMails = cantMails -1;
		manejadorConf.guardarCantidadMails(cantMails);
		vector<string> indices = manejadorConf.obtenerIndices();
		for(int i=0; i< indices.size(); i++){
			if (indices[i].find("SELECCION")!= -1){
				RegistroBSharp registroSeleccion;
				ArbolBSharp arbolSeleccion;
				const char* nombreArchivoIndice = indices[i].c_str();
				arbolSeleccion.Abrir((char*)nombreArchivoIndice);
				char archivo[indices[i].length()];
				strcpy(archivo, indices[i].c_str());
				arbolSeleccion.Abrir(archivo);
				registroSeleccion = arbolSeleccion.ObtenerRegistro(id);
				if (registro.clave != -1){
					arbolSeleccion.EliminarRegistro(id);
				}
			}
			if (indices[i].find("LISTA")!=-1){
				char strLista[indices[i].length()];
				strcpy(strLista, indices[i].c_str());
				ManejadorArchivoClasificacion lista(strLista,ABRIR);
				lista.eliminarIdDeLista(id);
			}
		}
		Diccionario dic;
		ManejadorListaPalabras listaPalabras(dic.archivoLista, ABRIR);
		listaPalabras.eliminarIdDeLista(id);
		return true;
	}	else{
	  return false;
	}
}

void ManejadorInstrucciones::MostrarDiccionario(QString &output) {
  Diccionario dic;
  vector<string> palabras = dic.mostrarDiccionario();
  if (palabras.size() < 1) {
    output += "El diccionario esta vacio.";
  } else {
    QString palabra;
    for (unsigned int i = 0; i < palabras.size(); i++) {
      palabra.clear();
      palabra = QString("    Palabra %1: ")
          .arg(i);
      palabra.append(palabras[i].c_str());
      palabra.append("\n");
      output += palabra;
    }
  }
}

vector<ModeloDocumento> ManejadorInstrucciones::buscarTermino(vector<string> terminos) {
	Diccionario dic;
	vector<ModeloDocumento> enc = dic.buscarTerminos(terminos);
	return enc;
}

vector<ModeloDocumento> ManejadorInstrucciones::buscarFrase(vector<PalabraPos> terminos) {
	Diccionario dic;
	vector<ModeloDocumento> enc = dic.buscarFrase(terminos);
	return enc;
}


ManejadorInstrucciones::~ManejadorInstrucciones() {
}
